#include "Pwm.h"
#include "device.h"

static OCregisters * const OCmodules[] = {
    MODULE_OC1, MODULE_OC2, MODULE_OC3, MODULE_NULL
};

VTABLE(Pwm, PeripheralModule)
    VMETHOD(Object, dtor) = (void (*)(Object *))&Pwm_dtor;
    VMETHOD(PeripheralModule, dtor) = (void (*)(PeripheralModule *))&Pwm_dtor;
    VMETHOD(Pwm, dtor) = (void (*)(Pwm *))&Pwm_dtor;
VTABLE_END

void Pwm_ctor(Pwm *obj, int module, int dutyCycleValue, int maximumValue) {
    _PeripheralModule_ctor(&obj->super);
    VHOOK(Pwm);
    int length;
    for(length = 0; OCmodules[length] != MODULE_NULL; length++);
    if((module < 0) || (module >= length)) { return; }
    obj->super._module = module;
    OCmodules[module]->CON1.word = 0;             /* Reset control register.  */
    OCmodules[module]->CON2.word = 0;             /* Reset control register.  */
    OCmodules[module]->CON1.bits.OCTSEL = 0x7;    /* Select system clock.     */
    OCmodules[module]->CON2.bits.SYNCSEL = 0x1F;  /* Sync with itself.        */
    OCmodules[module]->R = dutyCycleValue;        /* Set duty cycle.          */
    OCmodules[module]->RS = maximumValue;         /* Set period.              */
    OCmodules[module]->CON1.bits.OCM = 0x6;       /* Start edge-aligned mode. */
}

void Pwm_dtor(Pwm *obj) {
    if(_PeripheralModule_isValid(&obj->super)) {
        OCmodules[obj->super._module]->CON1.word = 0;
        OCmodules[obj->super._module]->CON2.word = 0;
        OCmodules[obj->super._module]->R = 0;
        OCmodules[obj->super._module]->RS = 0;
    }
    _PeripheralModule_dtor(&obj->super);
}

void Pwm_setDutyCycle(Pwm *obj, int value) {
    if(!_PeripheralModule_isValid(&obj->super)) { return; }
    OCmodules[obj->super._module]->R = value;
}
